
//////////////////////////////////////////////////////////////////////////////////
// Company:
// Engineer:
//
// Create Date: 2023/05/02
// Design Name:
// Module Name: tm_apb_if
// Project Name: wujian100
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// base ahb addr is 0x6003_0000  none offset
//////////////////////////////////////////////////////////////////////////////////
//t2r_mailbox_top模块状态机个数
`define T2R_BOOT_NUM        5


module sram_apb                                                               //没有ready信号，在mux中将ready信号全部拉高
    (
    input                              sram_clk_i,
    input                              sram_rst_n_i,

    input                 [32 - 1 : 0] sram_paddr_i,
    input                 [3  - 1 : 0] sram_pprot_i,                       
    input                 [1  - 1 : 0] sram_psel_i,
    input                 [1  - 1 : 0] sram_pen_i,
    input                 [32 - 1 : 0] sram_pwdata_i,
    input                 [1  - 1 : 0] sram_pwrite_i,

    output                [32 - 1 : 0] sram_prdata_o,
    output                [1  - 1 : 0] sram_t2r_intr_o
    );

wire                      [1  - 1 : 0] t2r_clk_w;
wire                      [1  - 1 : 0] t2r_rst_n_w;
wire                      [1  - 1 : 0] t2r_w_en_w;
wire                      [1  - 1 : 0] t2r_r_en_w;
wire                      [12 - 1 : 0] t2r_addr_w;
wire                      [32 - 1 : 0] t2r_wdat_w;

wire                      [1  - 1 : 0] t2r_rdy_w;
wire                      [32 - 1 : 0] t2r_rdat_w;
wire                      [1  - 1 : 0] t2r_intr_w;

//////////////////////////////////////
//本地参数                           //
//////////////////////////////////////

localparam PORT_FIELD                  = 0;                                    //标志PORT信号的第几位是有效位
localparam ADDR_W                      = 12;                                   //子模块地址信号位宽，与分配地址空间有关

localparam IDLE                        = `T2R_BOOT_NUM'b00000;                 //空闲状态
localparam WRITE_CMD                   = `T2R_BOOT_NUM'b00001;                 //写指令状态
localparam READ_CMD                    = `T2R_BOOT_NUM'b00010;                 //读指令状态
localparam WRITE_DAT                   = `T2R_BOOT_NUM'b00100;                 //写数据状态
localparam READ_DAT                    = `T2R_BOOT_NUM'b01000;                 //读数据状态
localparam ERROR_RESP                  = `T2R_BOOT_NUM'b10000;                 //违规请求响应状态

//////////////////////////////////////
//状态机信号                         //
//////////////////////////////////////

reg     [`T2R_BOOT_NUM-1:0] state_c;
reg     [`T2R_BOOT_NUM-1:0] state_n;

reg        [32 - 1 : 0] sram_paddr_r;
reg        [32 - 1 : 0] sram_pwdata_r;
reg        [32 - 1 : 0] sram_prdata_r;

//////////////////////////////////////
//违规请求标志信号                    //
//////////////////////////////////////

wire                    error_req_flag_w;                                      //错误请求标志线

//////////////////////////////////////
//读写使能信号                       //
//////////////////////////////////////

wire                    w_en;                                                  //写使能标志
wire                    r_en;                                                  //读使能标志
wire                    en;                                                    //使能信号
wire                    handshake;                                             //握手信号
wire                    en_box;
wire                    write_box;


//////////////////////////////////////
//ree core复位地址                   //
//////////////////////////////////////

reg                     init_ree_ifu_pc_addr_en;
reg            [32-1:0] init_ree_ifu_pc_addr;

reg                     init_ree_ifu_en_en;
reg            [32-1:0] init_ree_ifu_en;

reg                     init_ree_ifu_len_en;
reg            [32-1:0] init_ree_ifu_len;

reg                     init_ree_iram_base_addr_en;
reg            [32-1:0] init_ree_iram_base_addr;

/************************************/
/*系统信号                           */
/************************************/

assign t2r_clk_w        = sram_clk_i;
assign t2r_rst_n_w      = sram_rst_n_i;

/************************************/
/*读写使能信号                       */
/************************************/
assign handshake        = ((sram_psel_i == 1'b1)&&
                           (sram_pen_i == 1'b0)) ? 1'b1 : 1'b0;

assign w_en             = ((handshake == 1'b1)&&
                           (sram_pwrite_i == 1'b1)&&
                           (error_req_flag_w == 1'b0)) ? 1'b1 : 1'b0;

assign r_en             = ((handshake == 1'b1)&&
                           (sram_pwrite_i == 1'b0)&&
                           (error_req_flag_w == 1'b0)) ? 1'b1 : 1'b0;

assign en               = ((w_en == 1'b1)||(r_en == 1'b1)) ? 1'b1 : 1'b0;

/************************************/
/*违规请求标志                       */
/************************************/

assign error_req_flag_w = 1'b0;
/************************************/
/*状态机                            */
/************************************/

/*************part 1*************/
always@(posedge sram_clk_i or negedge sram_rst_n_i)                              //当前状态
begin : STATE_C_PROG
  if (sram_rst_n_i == 1'b0)
    state_c             <= {(`T2R_BOOT_NUM){1'b0}};
  else
    state_c             <= state_n;
end

/*************part 2*************/
always@(*)                                                                     //状态转换
begin : STATE_N_PROG
  case (state_c)
	IDLE        :
    begin
	  if (error_req_flag_w == 1'b1)                                            //如果出现违规请求
	    state_n         = ERROR_RESP;                                          //转换到错误响应状态
	  else if (w_en == 1'b1)                                                   //如果写使能
	    state_n         = WRITE_CMD;                                           //转换到写命令状态
	  else if (r_en == 1'b1)                                                   //如果读使能
	    state_n         = READ_CMD;                                            //转换到读命令状态
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //空闲状态
	end
    WRITE_CMD   :
	begin
	  if (sram_pen_i == 1'b1)                                                   //如果从机准备好
	    state_n         = WRITE_DAT;                                           //写数据
	  else                                                                     //其它情况
	    state_n         = ERROR_RESP;                                          //返回错误响应
	end
    READ_CMD    :
	begin
	  if (sram_pen_i == 1'b1)                                                   //如果从机准备好
	    state_n         = READ_DAT;                                            //读数据
	  else                                                                     //其它情况
	    state_n         = ERROR_RESP;                                          //返回错误响应
	end
    WRITE_DAT   :
    begin
      if (w_en == 1'b1)                                                        //如果在写数据的时候主机已发送下一组写指令
	    state_n         = WRITE_CMD;                                           //转换到写指令
	  else if (r_en == 1'b1)                                                   //如果在写数据的时候主机已发送下一组读指令
	    state_n         = READ_CMD;                                            //转换到读指令
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //转换到空闲状态
	end
    READ_DAT    :
    begin
      if (r_en == 1'b1)                                                        //如果在写数据的时候主机已发送下一组读指令
	    state_n         = READ_CMD;                                            //转换到读指令
	  else if (w_en == 1'b1)                                                   //如果在写数据的时候主机已发送下一组写指令
	    state_n         = WRITE_CMD;                                           //转换到写指令
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //转换到空闲状态
	end
    ERROR_RESP  :
    begin
      if (r_en == 1'b1)                                                        //如果在写数据的时候主机已发送下一组读指令
	    state_n         = READ_CMD;                                            //转换到读指令
	  else if (w_en == 1'b1)                                                   //如果在写数据的时候主机已发送下一组写指令
	    state_n         = WRITE_CMD;                                           //转换到写指令
	  else                                                                     //其它情况
	    state_n         = IDLE;                                                //转换到空闲状态
	end
	default     :
      state_n           = IDLE;
  endcase
end

/*************part 3*************/

always@(posedge sram_clk_i or negedge sram_rst_n_i)
begin : sram_PADDR_R_PROG
  if (sram_rst_n_i == 1'b0)                                                     //复位信号有效
    sram_paddr_r         <= {(32){1'b0}};                                       //复位
  else if ((state_c == IDLE)&&(en == 1'b1))                                    //当前为空闲状态，并且有指令路由过来时
    sram_paddr_r         <= sram_paddr_i;                                        //将指令信号寄存
  else                                                                         //其它情况
    sram_paddr_r         <= sram_paddr_r;                                        //保持
end

always@(*)
begin : sram_PWDATA_R_PROG
  if (t2r_w_en_w == 1'b1)                                                    //当前为写指令，并且下一个状态为写数据
    sram_pwdata_r         = sram_pwdata_i;                                       //将指令信号寄存
  else                                                                         //其它情况
    sram_pwdata_r         = {(32){1'b0}};                                       //无效
end

always@(*)
begin : sram_PRDATA_R_PROG
  if (t2r_r_en_w == 1'b1)                                                      //当前为读数据状态
    sram_prdata_r        = t2r_rdat_w;                                          //响应读数据
  else                                                                         //其它情况
    sram_prdata_r        = {(32){1'b0}};                                        //归零
end


/************************************/
/*AHB写控制信号                      */
/************************************/

assign t2r_addr_w       = sram_paddr_r;                                         //由状态机控制
assign t2r_wdat_w       = sram_pwdata_r;                                        //由状态机控制
assign t2r_w_en_w       = ((state_c == WRITE_CMD)&&(state_n == WRITE_DAT)) ? 1'b1 : 1'b0;//由于apb总线上的从机无法通过ready信号控制延迟，因此采用更紧的时序
assign t2r_r_en_w       = ((state_c == READ_CMD)&&(state_n == READ_DAT)) ? 1'b1 : 1'b0;  //由于apb总线上的从机无法通过ready信号控制延迟，因此采用更紧的时序
assign en_box           = t2r_r_en_w|t2r_w_en_w;
assign write_box        = ((t2r_r_en_w == 1'b0) && (t2r_w_en_w == 1'b1)) ? 1'b1 : 1'b0;
/************************************/
/*AHB读控制信号                      */
/************************************/

//在接收到违规请求之后，下一个时钟周期返回错误响应
assign sram_prdata_o     = sram_prdata_r;                                        //读数据信号由状态机控制

assign sram_t2r_intr_o   = t2r_intr_w;



/************************************/
/*例化子模块                         */
/************************************/

spram_simple
   #(
    .ADDR_W                            (ADDR_W                                 )
    )
u_tm_tee2ree_box
    (
    .clk_i                             (t2r_clk_w                              ),
    .rst_n_i                           (t2r_rst_n_w                            ),
    .en_i                              (en_box                                 ),
    .write_i                           (write_box                              ),
    .addr_i                            (t2r_addr_w                             ),
    .wdat_i                            (t2r_wdat_w                             ),
    .rdy_o                             (t2r_rdy_w                              ),
    .rdat_o                            (t2r_rdat_w                             ),
    .intr_o                            (t2r_intr_w                             )    //硬件清除中断标志位，持续一个时钟周期
    );

endmodule

